{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cSrJYrFrY2aj"
      },
      "source": [
        "##### Copyright 2024 Google LLC."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "cellView": "form",
        "id": "i1PHqD-ZY4-c"
      },
      "outputs": [],
      "source": [
        "# @title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YNDq8NbCY7oh"
      },
      "source": [
        "# How to Fine-tuning Gemma for Spoken Language Tasks\n",
        "\n",
        "This notebook demonstrate how to fine tune Gemma for the specific task on replying to email requests that a Korean bakery business might get.\n",
        "\n",
        "<table align=\"left\">\n",
        "  <td>\n",
        "    <a target=\"_blank\" href=\"https://colab.research.google.com/github/google-gemini/gemma-cookbook/blob/main/Demos/spoken-language-tasks/k-gemma-it/spoken_language_tasks_with_gemma.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\" />Run in Google Colab</a>\n",
        "  </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3rzH5Ugf5RlJ"
      },
      "source": [
        "## Setup\n",
        "\n",
        "### Select the Colab runtime\n",
        "To complete this tutorial, you'll need to have a Colab runtime with sufficient resources to run the Gemma model:\n",
        "\n",
        "1. In the upper-right of the Colab window, select **▾ (Additional connection options)**.\n",
        "2. Select **Change runtime type**.\n",
        "3. Under **Hardware accelerator**, select **L4** or **A100 GPU**.\n",
        "\n",
        "\n",
        "### Gemma setup on Kaggle\n",
        "To complete this tutorial, you'll first need to complete the setup instructions at [Gemma setup](https://ai.google.dev/gemma/docs/setup). The Gemma setup instructions show you how to do the following:\n",
        "\n",
        "* Get access to Gemma on kaggle.com.\n",
        "* Select a Colab runtime with sufficient resources to run the Gemma 2B model.\n",
        "* Generate and configure a Kaggle username and API key.\n",
        "\n",
        "After you've completed the Gemma setup, move on to the next section, where you'll set environment variables for your Colab environment."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "URMuBzkMVxpU"
      },
      "source": [
        "### Set environment variables\n",
        "\n",
        "Set environement variables for ```KAGGLE_USERNAME``` and ```KAGGLE_KEY```."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IUOX2hqjV7Ku"
      },
      "outputs": [],
      "source": [
        "import os\n",
        "from google.colab import userdata, drive\n",
        "\n",
        "# Note: `userdata.get` is a Colab API. If you're not using Colab, set the env\n",
        "# vars as appropriate for your system.\n",
        "os.environ[\"KAGGLE_USERNAME\"] = userdata.get(\"KAGGLE_USERNAME\")\n",
        "os.environ[\"KAGGLE_KEY\"] = userdata.get(\"KAGGLE_KEY\")\n",
        "\n",
        "# Mounting gDrive for to store artifacts\n",
        "drive.mount(\"/content/drive\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "LXfDwRTQVns2"
      },
      "source": [
        "### Install dependencies\n",
        "\n",
        "Install Keras and KerasNLP"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "id": "zHs7wpZusEML"
      },
      "outputs": [],
      "source": [
        "!pip install -q -U keras-nlp datasets\n",
        "!pip install -q -U keras\n",
        "\n",
        "# Set the backbend before importing Keras\n",
        "os.environ[\"KERAS_BACKEND\"] = \"jax\"\n",
        "# Avoid memory fragmentation on JAX backend.\n",
        "os.environ[\"XLA_PYTHON_CLIENT_MEM_FRACTION\"] = \"1.00\"\n",
        "\n",
        "import keras_nlp\n",
        "import keras\n",
        "\n",
        "# Run at half precision.\n",
        "#keras.config.set_floatx(\"bfloat16\")\n",
        "\n",
        "# Training Configurations\n",
        "token_limit = 512\n",
        "num_data_limit = 100\n",
        "lora_name = \"cakeboss\"\n",
        "lora_rank = 4\n",
        "lr_value = 1e-4\n",
        "train_epoch = 20\n",
        "model_id = \"gemma2_instruct_2b_en\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kUl0t469YfQY"
      },
      "source": [
        "## Load Model"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "id": "Gm4jIEqmYfQY"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Preprocessor: \"gemma_causal_lm_preprocessor\"</span>\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1mPreprocessor: \"gemma_causal_lm_preprocessor\"\u001b[0m\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃<span style=\"font-weight: bold\"> Layer (type)                                                  </span>┃<span style=\"font-weight: bold\">                                   Config </span>┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ gemma_tokenizer (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GemmaTokenizer</span>)                              │                      Vocab size: <span style=\"color: #00af00; text-decoration-color: #00af00\">256,000</span> │\n",
              "└───────────────────────────────────────────────────────────────┴──────────────────────────────────────────┘\n",
              "</pre>\n"
            ],
            "text/plain": [
              "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                                                 \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m                                  Config\u001b[0m\u001b[1m \u001b[0m┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ gemma_tokenizer (\u001b[38;5;33mGemmaTokenizer\u001b[0m)                              │                      Vocab size: \u001b[38;5;34m256,000\u001b[0m │\n",
              "└───────────────────────────────────────────────────────────────┴──────────────────────────────────────────┘\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"gemma_causal_lm\"</span>\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1mModel: \"gemma_causal_lm\"\u001b[0m\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃<span style=\"font-weight: bold\"> Layer (type)                  </span>┃<span style=\"font-weight: bold\"> Output Shape              </span>┃<span style=\"font-weight: bold\">         Param # </span>┃<span style=\"font-weight: bold\"> Connected to               </span>┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ padding_mask (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)     │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>)              │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_ids (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)        │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>)              │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ gemma_backbone                │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">2304</span>)        │   <span style=\"color: #00af00; text-decoration-color: #00af00\">2,614,341,888</span> │ padding_mask[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>],        │\n",
              "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GemmaBackbone</span>)               │                           │                 │ token_ids[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]            │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_embedding               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256000</span>)      │     <span style=\"color: #00af00; text-decoration-color: #00af00\">589,824,000</span> │ gemma_backbone[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]       │\n",
              "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">ReversibleEmbedding</span>)         │                           │                 │                            │\n",
              "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n",
              "</pre>\n"
            ],
            "text/plain": [
              "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                 \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape             \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m        Param #\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mConnected to              \u001b[0m\u001b[1m \u001b[0m┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ padding_mask (\u001b[38;5;33mInputLayer\u001b[0m)     │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m)              │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_ids (\u001b[38;5;33mInputLayer\u001b[0m)        │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m)              │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ gemma_backbone                │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2304\u001b[0m)        │   \u001b[38;5;34m2,614,341,888\u001b[0m │ padding_mask[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m],        │\n",
              "│ (\u001b[38;5;33mGemmaBackbone\u001b[0m)               │                           │                 │ token_ids[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]            │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_embedding               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256000\u001b[0m)      │     \u001b[38;5;34m589,824,000\u001b[0m │ gemma_backbone[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]       │\n",
              "│ (\u001b[38;5;33mReversibleEmbedding\u001b[0m)         │                           │                 │                            │\n",
              "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">2,614,341,888</span> (9.74 GB)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m2,614,341,888\u001b[0m (9.74 GB)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">2,614,341,888</span> (9.74 GB)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m2,614,341,888\u001b[0m (9.74 GB)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "##  답장 예시\n",
            "\n",
            "**제목: Re: 결혼기념일 케이크 주문 문의**\n",
            "\n",
            "안녕하세요, [주문자 이름]님,\n",
            "\n",
            "안녕하세요. 결혼기념일 케이크 주문을 받으셨네요! 😊 \n",
            "\n",
            "3호 케이크 1개를 주문하시는군요. \n",
            "\n",
            "[주문자 이름]님의 결혼기념일을 축하드립니다! \n",
            "\n",
            "[케이크 종류, 옵션, 주문 날짜 등]에 대한 자세한 정보를 알려주시면 최대한 멋진 케이크를 만들어 드리겠습니다. \n",
            "\n",
            "[주문자 이름]님께서 원하는 케이크의 디자인, 옵션, 주문 날짜 등을 알려주시면 됩니다. \n",
            "\n",
            "[주문자 이름]님께서 원하는 케이크를 만들어 드리겠습니다. \n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[이름]\n",
            "[회사명/전화번호/이메일 주소] \n",
            "\n",
            "\n",
            "**참고:**\n",
            "\n",
            "* 위 답장은 예시이며, 실제 답장에 필요한 내용을 추가하거나 수정해야 할 수 있습니다. \n",
            "* 케이크 종류, 옵션, 주문 날짜 등을 명확하게 알려주는 것이 중요합니다. \n",
            "* 답장에 친절하고 긍정적인 분위기를 유지하는 것이 좋습니다. \n",
            "* 케이크 주문에 대한 추가 질문이 있으면 언제든지 문의해주세요. \n",
            "\n",
            "\n",
            "\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 41.09s\n"
          ]
        }
      ],
      "source": [
        "import keras\n",
        "import keras_nlp\n",
        "\n",
        "import time\n",
        "\n",
        "gemma_lm = keras_nlp.models.GemmaCausalLM.from_preset(model_id)\n",
        "gemma_lm.summary()\n",
        "\n",
        "tick_start = 0\n",
        "\n",
        "def tick():\n",
        "    global tick_start\n",
        "    tick_start = time.time()\n",
        "\n",
        "def tock():\n",
        "    print(f\"TOTAL TIME ELAPSED: {time.time() - tick_start:.2f}s\")\n",
        "\n",
        "def text_gen(prompt):\n",
        "    tick()\n",
        "    input = f\"<start_of_turn>user\\n{prompt}<end_of_turn>\\n<start_of_turn>model\\n\"\n",
        "    output = gemma_lm.generate(input, max_length=token_limit)\n",
        "    print(\"\\nGemma output:\")\n",
        "    print(output)\n",
        "    tock()\n",
        "\n",
        "# inference before fine-tuning\n",
        "text_gen(\"다음에 대한 이메일 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9T7xe_jzslv4"
      },
      "source": [
        "## Load Dataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "ZiS-KU9osh_N"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "1697225eea94485bad28b735a23036fe",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "README.md:   0%|          | 0.00/61.0 [00:00<?, ?B/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "cec38576c6b9402bada9c347b2ac8ca0",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "train.csv:   0%|          | 0.00/14.9k [00:00<?, ?B/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "application/vnd.jupyter.widget-view+json": {
              "model_id": "4f0b0579b4334fc0acdf4beb1a2bbb25",
              "version_major": 2,
              "version_minor": 0
            },
            "text/plain": [
              "Generating train split:   0%|          | 0/20 [00:00<?, ? examples/s]"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Dataset({\n",
            "    features: ['input', 'output'],\n",
            "    num_rows: 20\n",
            "})\n",
            "20\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요,\n",
            "2주 뒤에 있을 아이 생일을 위해 3호 케이크 3개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "2주 뒤 아이 생일을 위한 3호 케이크 2개 주문 문의 감사합니다.\n",
            "네, 3호 케이크 2개 주문 가능합니다.\n",
            "\n",
            "아이 생일 케이크인 만큼 더욱 신경 써서 정성껏 준비하겠습니다. 혹시 원하시는 디자인이나 특별한 요청 사항이 있으시면 편하게 말씀해주세요.\n",
            "\n",
            "픽업 날짜와 시간을 알려주시면 더욱 자세한 안내를 도와드리겠습니다.\n",
            "\n",
            "다시 한번 문의 감사드리며, 아이 생일 진심으로 축하합니다!\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요,\n",
            "\n",
            "9월 15일에 있을 아들의 돌잔치를 위해 케이크를 주문하고 싶습니다.\n",
            "- 케이크 종류: 생크림 케이크\n",
            "- 크기: 2호\n",
            "- 디자인: 아기자기한 동물 디자인\n",
            "- 문구: \"첫 생일 축하해, 사랑하는 아들!\"\n",
            "- 픽업 날짜 및 시간: 9월 14일 오후 3시\n",
            "\n",
            "가격 및 주문 가능 여부를 알려주시면 감사하겠습니다.\n",
            "\n",
            "감사합니다.\n",
            "김민지 드림\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요, 김민지 님,\n",
            "\n",
            "9월 15일 아드님의 돌잔치를 위한 케이크 주문 문의 감사합니다.\n",
            "\n",
            "- 생크림 케이크 2호, 아기자기한 동물 디자인, \"첫 생일 축하해, 사랑하는 아들!\" 문구, 9월 14일 오후 3시 픽업 모두 가능합니다.\n",
            "- 가격은 5만원입니다.\n",
            "\n",
            "주문을 원하시면 연락 주세요.\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 박지혜라고 합니다.\n",
            "\n",
            "10월 5일에 있을 결혼 10주년 기념일을 위해 특별한 디자인의 케이크를 주문하고 싶습니다.\n",
            "\n",
            "케이크 종류: 레드벨벳 케이크\n",
            "크기: 3호\n",
            "디자인: 첨부된 사진처럼 웨딩드레스와 턱시도 모양으로 장식된 케이크\n",
            "맞춤 디자인 제작이 가능한지, 그리고 예상 가격과 제작 기간을 알려주시면 감사하겠습니다.\n",
            "\n",
            "감사합니다.\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요, 박지혜 님,\n",
            "\n",
            "결혼 10주년 기념일을 위한 특별한 케이크 주문 문의 감사합니다.\n",
            "\n",
            "첨부해주신 사진과 같은 웨딩드레스 & 턱시도 디자인의 레드벨벳 케이크 3호 제작 가능합니다.\n",
            "추가로 원하시는 특별한 문구가 있다면 넣어드릴 수 있습니다.\n",
            "맞춤 디자인 제작으로, 가격은 12만원이며 제작 기간은 3일 정도 소요됩니다.\n",
            "픽업 날짜와 시간을 알려주시면 그에 맞춰 제작하겠습니다.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n"
          ]
        }
      ],
      "source": [
        "import keras\n",
        "import keras_nlp\n",
        "import datasets\n",
        "\n",
        "tokenizer = keras_nlp.models.GemmaTokenizer.from_preset(model_id)\n",
        "\n",
        "# prompt structure\n",
        "# <start_of_turn>user\n",
        "# 다음에 대한 이메일 답장을 작성해줘.\n",
        "# \"{EMAIL CONTENT FROM THE CUSTOMER}\"\n",
        "# <end_of_turn>\n",
        "# <start_of_turn>model\n",
        "# {MODEL ANSWER}<end_of_turn>\n",
        "\n",
        "# input, output\n",
        "from datasets import load_dataset\n",
        "ds = load_dataset(\n",
        "    \"bebechien/korean_cake_boss\",\n",
        "    split=\"train\",\n",
        ")\n",
        "print(ds)\n",
        "data = ds.with_format(\"np\", columns=[\"input\", \"output\"], output_all_columns=False)\n",
        "train = []\n",
        "\n",
        "for x in data:\n",
        "  item = f\"<start_of_turn>user\\n다음에 대한 이메일 답장을 작성해줘.\\n\\\"{x['input']}\\\"<end_of_turn>\\n<start_of_turn>model\\n{x['output']}<end_of_turn>\"\n",
        "  length = len(tokenizer(item))\n",
        "  # skip data if the token length is longer than our limit\n",
        "  if length < token_limit:\n",
        "    train.append(item)\n",
        "    if(len(train)>=num_data_limit):\n",
        "      break\n",
        "\n",
        "print(len(train))\n",
        "print(train[0])\n",
        "print(train[1])\n",
        "print(train[2])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Pt7Nr6a7tItO"
      },
      "source": [
        "## LoRA Fine-tuning"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "RCucu6oHz53G"
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Preprocessor: \"gemma_causal_lm_preprocessor\"</span>\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1mPreprocessor: \"gemma_causal_lm_preprocessor\"\u001b[0m\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃<span style=\"font-weight: bold\"> Layer (type)                                                  </span>┃<span style=\"font-weight: bold\">                                   Config </span>┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ gemma_tokenizer (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GemmaTokenizer</span>)                              │                      Vocab size: <span style=\"color: #00af00; text-decoration-color: #00af00\">256,000</span> │\n",
              "└───────────────────────────────────────────────────────────────┴──────────────────────────────────────────┘\n",
              "</pre>\n"
            ],
            "text/plain": [
              "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                                                 \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m                                  Config\u001b[0m\u001b[1m \u001b[0m┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ gemma_tokenizer (\u001b[38;5;33mGemmaTokenizer\u001b[0m)                              │                      Vocab size: \u001b[38;5;34m256,000\u001b[0m │\n",
              "└───────────────────────────────────────────────────────────────┴──────────────────────────────────────────┘\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"gemma_causal_lm\"</span>\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1mModel: \"gemma_causal_lm\"\u001b[0m\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃<span style=\"font-weight: bold\"> Layer (type)                  </span>┃<span style=\"font-weight: bold\"> Output Shape              </span>┃<span style=\"font-weight: bold\">         Param # </span>┃<span style=\"font-weight: bold\"> Connected to               </span>┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ padding_mask (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)     │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>)              │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_ids (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>)        │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>)              │               <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ gemma_backbone                │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">2304</span>)        │   <span style=\"color: #00af00; text-decoration-color: #00af00\">2,617,270,528</span> │ padding_mask[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>],        │\n",
              "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GemmaBackbone</span>)               │                           │                 │ token_ids[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]            │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_embedding               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256000</span>)      │     <span style=\"color: #00af00; text-decoration-color: #00af00\">589,824,000</span> │ gemma_backbone[<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>][<span style=\"color: #00af00; text-decoration-color: #00af00\">0</span>]       │\n",
              "│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">ReversibleEmbedding</span>)         │                           │                 │                            │\n",
              "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n",
              "</pre>\n"
            ],
            "text/plain": [
              "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓\n",
              "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                 \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape             \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m        Param #\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mConnected to              \u001b[0m\u001b[1m \u001b[0m┃\n",
              "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩\n",
              "│ padding_mask (\u001b[38;5;33mInputLayer\u001b[0m)     │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m)              │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_ids (\u001b[38;5;33mInputLayer\u001b[0m)        │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m)              │               \u001b[38;5;34m0\u001b[0m │ -                          │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ gemma_backbone                │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m2304\u001b[0m)        │   \u001b[38;5;34m2,617,270,528\u001b[0m │ padding_mask[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m],        │\n",
              "│ (\u001b[38;5;33mGemmaBackbone\u001b[0m)               │                           │                 │ token_ids[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]            │\n",
              "├───────────────────────────────┼───────────────────────────┼─────────────────┼────────────────────────────┤\n",
              "│ token_embedding               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256000\u001b[0m)      │     \u001b[38;5;34m589,824,000\u001b[0m │ gemma_backbone[\u001b[38;5;34m0\u001b[0m][\u001b[38;5;34m0\u001b[0m]       │\n",
              "│ (\u001b[38;5;33mReversibleEmbedding\u001b[0m)         │                           │                 │                            │\n",
              "└───────────────────────────────┴───────────────────────────┴─────────────────┴────────────────────────────┘\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">2,617,270,528</span> (9.75 GB)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m2,617,270,528\u001b[0m (9.75 GB)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">2,928,640</span> (11.17 MB)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m2,928,640\u001b[0m (11.17 MB)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "data": {
            "text/html": [
              "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">2,614,341,888</span> (9.74 GB)\n",
              "</pre>\n"
            ],
            "text/plain": [
              "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m2,614,341,888\u001b[0m (9.74 GB)\n"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "# Enable LoRA for the model and set the LoRA rank to 4.\n",
        "gemma_lm.backbone.enable_lora(rank=lora_rank)\n",
        "gemma_lm.summary()\n",
        "\n",
        "# Limit the input sequence length (to control memory usage).\n",
        "gemma_lm.preprocessor.sequence_length = token_limit\n",
        "# Use AdamW (a common optimizer for transformer models).\n",
        "optimizer = keras.optimizers.AdamW(\n",
        "    learning_rate=lr_value,\n",
        "    weight_decay=0.01,\n",
        ")\n",
        "# Exclude layernorm and bias terms from decay.\n",
        "optimizer.exclude_from_weight_decay(var_names=[\"bias\", \"scale\"])\n",
        "\n",
        "gemma_lm.compile(\n",
        "    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "    optimizer=optimizer,\n",
        "    weighted_metrics=[keras.metrics.SparseCategoricalAccuracy()],\n",
        ")\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hQQ47kcdpbZ9"
      },
      "source": [
        "Note that enabling LoRA reduces the number of trainable parameters significantly."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 9,
      "metadata": {
        "id": "26d9npFhAOSp"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Epoch 1/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - loss: 1.1019 - sparse_categorical_accuracy: 0.5969\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "##  답장 예시\n",
            "\n",
            "**제목: Re: 결혼기념일 케이크 주문 문의**\n",
            "\n",
            "안녕하세요, [주문자 이름]님,\n",
            "\n",
            "안녕하세요. 결혼기념일 케이크 주문을 받으셨네요! 😊 \n",
            "\n",
            "3호 케이크 1개를 주문하시면, 멋진 결혼기념일을 축하드립니다! \n",
            "\n",
            "[주문 내용에 대한 추가 정보를 적어주세요. 예시: 케이크 종류, 크기, 디자인, 주문 날짜, 배송 지역 등]\n",
            "\n",
            "[주문 가능 여부에 대한 답변]\n",
            "\n",
            "* 케이크 주문이 가능합니다. \n",
            "* [케이크 주문 가능 여부에 대한 추가 설명]\n",
            "\n",
            "[케이크 주문 시 추가 정보를 요청할 수 있는 문구]\n",
            "\n",
            "* [예시: 케이크 디자인에 대한 추가 설명, 배송 날짜, 배송 지역 등]\n",
            "\n",
            "[주문에 대한 답변을 위한 추가 문구]\n",
            "\n",
            "* [예시: 케이크 주문이 완료되었는지 확인해주세요.]\n",
            "\n",
            "감사합니다. \n",
            "\n",
            "[이름]\n",
            "\n",
            "[회사/개인 정보]\n",
            "\n",
            "\n",
            "**참고:**\n",
            "\n",
            "* 위 답변은 예시이며, 실제 답변에 따라 내용을 수정해야 합니다. \n",
            "* 케이크 주문에 대한 추가 정보를 적어주세요. \n",
            "* 답변에 대한 질문이 있으면 언제든지 문의해주세요. \n",
            "\n",
            "\n",
            "\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 39.27s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m128s\u001b[0m 8s/step - loss: 1.1012 - sparse_categorical_accuracy: 0.5964\n",
            "Epoch 2/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 643ms/step - loss: 1.0636 - sparse_categorical_accuracy: 0.6019\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. \n",
            "\n",
            "결혼기념일 케이크 주문을 환영합니다! 3호 케이크 1개를 주문하시는군요. 😊\n",
            "\n",
            "[주문 가능 여부에 따라 답변]\n",
            "\n",
            "* **가능합니다.**  [케이크 종류, 크기, 디자인 등에 대한 자세한 정보를 추가]\n",
            "* **죄송합니다.** [케이크 주문 가능 여부에 대한 자세한 설명]\n",
            "\n",
            "[주문 가능 여부에 대한 추가 정보]\n",
            "\n",
            "* 주문 가능한 날짜와 시간은 [날짜와 시간]입니다.\n",
            "* 케이크 가격은 [가격]입니다.\n",
            "* 케이크에 대한 추가 정보는 [주문자에게 추가 정보를 제공]\n",
            "\n",
            "[케이크 주문을 위한 추가 정보]\n",
            "\n",
            "* 케이크 주문을 위해 [주문 방법]을 이용해주세요.\n",
            "* [주문자에게 추가 정보를 제공]\n",
            "\n",
            "[케이크 주문에 대한 질문]\n",
            "\n",
            "* [주문자에게 질문]\n",
            "\n",
            "\n",
            " \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 11.96s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m45s\u001b[0m 2s/step - loss: 1.0623 - sparse_categorical_accuracy: 0.6016  \n",
            "Epoch 3/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 651ms/step - loss: 1.0042 - sparse_categorical_accuracy: 0.6117\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. \n",
            "\n",
            "결혼기념일 케이크 주문을 환영합니다! 3호 케이크 1개를 주문하시면 됩니다. \n",
            "\n",
            "[주문 내용에 대한 추가 정보를 입력하세요. 예시: 케이크 종류, 크기, 옵션 등]\n",
            "\n",
            "[주문 가능한 날짜와 시간을 입력하세요. 예시: 2023년 10월 28일 오후 2시부터]\n",
            "\n",
            "[주문 가능한 옵션을 입력하세요. 예시: 배송, 픽업 등]\n",
            "\n",
            "[주문 완료 후에 연락처를 입력하세요. 예시: 010-1234-5678]\n",
            "\n",
            "감사합니다. \n",
            "\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 8.84s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m16s\u001b[0m 2s/step - loss: 1.0023 - sparse_categorical_accuracy: 0.6116  \n",
            "Epoch 4/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 650ms/step - loss: 0.9292 - sparse_categorical_accuracy: 0.6305\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. \n",
            "\n",
            "결혼기념일 케이크 주문을 환영합니다! 3호 케이크 1개를 주문하시면 됩니다. \n",
            "\n",
            "[주문 가능한 케이크 종류 및 옵션]\n",
            "* [케이크 종류]\n",
            "* [케이크 크기]\n",
            "* [케이크 디자인]\n",
            "* [케이크 옵션]\n",
            "\n",
            "[주문 가능한 날짜 및 시간]\n",
            "* [주문 가능한 날짜]\n",
            "* [주문 가능한 시간]\n",
            "\n",
            "[주문 방법]\n",
            "* [주문 방법]\n",
            "\n",
            "[주문 확인]\n",
            "* [주문 확인]\n",
            "\n",
            "감사합니다. \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 7.77s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 2s/step - loss: 0.9271 - sparse_categorical_accuracy: 0.6304  \n",
            "Epoch 5/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 649ms/step - loss: 0.8567 - sparse_categorical_accuracy: 0.6446\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. 3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일 축하드립니다! \n",
            "주문하시면 곧 연락드리겠습니다. \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 2.67s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m9s\u001b[0m 961ms/step - loss: 0.8548 - sparse_categorical_accuracy: 0.6447\n",
            "Epoch 6/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.7944 - sparse_categorical_accuracy: 0.6753\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. 3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일 축하드립니다. \n",
            "주문하시면 곧 연락드리겠습니다. \n",
            "감사합니다. \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 2.98s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 992ms/step - loss: 0.7927 - sparse_categorical_accuracy: 0.6753\n",
            "Epoch 7/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 644ms/step - loss: 0.7377 - sparse_categorical_accuracy: 0.6891\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. 3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일 축하드립니다. \n",
            "주문하시면 곧 연락드리겠습니다. \n",
            "감사합니다. \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 2.97s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 989ms/step - loss: 0.7360 - sparse_categorical_accuracy: 0.6889\n",
            "Epoch 8/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.6835 - sparse_categorical_accuracy: 0.7020\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. 3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일 축하드립니다. \n",
            "주문하시면 맛있게 드실 수 있도록 최선을 다하겠습니다.\n",
            "주문하시면 몇 가지 추가 옵션을 알려드릴 수 있습니다.\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 4.10s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 1s/step - loss: 0.6818 - sparse_categorical_accuracy: 0.7019  \n",
            "Epoch 9/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 644ms/step - loss: 0.6318 - sparse_categorical_accuracy: 0.7216\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요.\n",
            "\n",
            "3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일을 축하드립니다.\n",
            "주문하시면 맛있게 드실 수 있도록 최선을 다하겠습니다.\n",
            "주문하시면 답장 드리겠습니다.\n",
            "\n",
            "감사합니다.\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.99s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 1s/step - loss: 0.6301 - sparse_categorical_accuracy: 0.7216  \n",
            "Epoch 10/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 644ms/step - loss: 0.5821 - sparse_categorical_accuracy: 0.7428\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요,\n",
            "\n",
            "3호 케이크 1개 주문 가능합니다. \n",
            "결혼기념일을 축하드립니다!\n",
            "주문하시면 \n",
            "* 케이크 종류: \n",
            "* 맛: \n",
            "* 글자: \n",
            "* 디자인: \n",
            "* 배송 날짜: \n",
            "등을 알려주시면 제작 가능합니다.\n",
            "\n",
            "감사합니다.\n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 4.81s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 1s/step - loss: 0.5804 - sparse_categorical_accuracy: 0.7427  \n",
            "Epoch 11/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 644ms/step - loss: 0.5329 - sparse_categorical_accuracy: 0.7624\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일을 위해 3호 케이크 1개 주문 가능합니다. \n",
            "다음과 같은 케이크를 제작할 수 있습니다.\n",
            "\n",
            "* 케이크 종류: 3호 케이크\n",
            "* 디자인: 결혼 기념일을 위한 디자인 (예: 결혼 날짜, 사진 등)\n",
            "* 옵션: \n",
            "    * 맛: 딸기, 초콜릿, 바닐라 등\n",
            "    * 장식: 꽃, 글자, 그림 등\n",
            "* 주문 가능 날짜: 2023년 10월 28일\n",
            "* 주문 가능 시간: 10:00 - 18:00\n",
            "* 주문 가능 금액: 15,000원\n",
            "\n",
            "다음과 같은 디자인을 원하시면, \n",
            "[디자인 요청]을 작성해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 11.07s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 2s/step - loss: 0.5311 - sparse_categorical_accuracy: 0.7624  \n",
            "Epoch 12/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 649ms/step - loss: 0.4876 - sparse_categorical_accuracy: 0.7834\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일을 위한 3호 케이크 주문 가능합니다. \n",
            "다음과 같은 케이크를 제작할 수 있습니다.\n",
            "\n",
            "* 케이크 종류: 3호 케이크\n",
            "* 디자인: 결혼 기념일을 위한 디자인 (예: 결혼 날짜, 사진 등)\n",
            "* 옵션: \n",
            "    * 글자 적용 (예: \"사랑하는 당신과 함께 10년을 맞이합니다.\")\n",
            "    * 장식 (예: 꽃, 깃털 등)\n",
            "* 주문 가능 날짜: 2023년 10월 28일\n",
            "* 주문 가능 시간: 10:00 - 18:00\n",
            "* 가격: 15,000원\n",
            "\n",
            "다음과 같은 디자인을 원하시나요?\n",
            "[가격, 디자인, 옵션 등을 포함한 이미지]\n",
            "\n",
            "감사합니다.<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 11.14s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m18s\u001b[0m 2s/step - loss: 0.4859 - sparse_categorical_accuracy: 0.7835  \n",
            "Epoch 13/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 650ms/step - loss: 0.4461 - sparse_categorical_accuracy: 0.8033\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. \n",
            "다음과 같은 케이크를 제작할 수 있습니다.\n",
            "\n",
            "* 케이크 종류: 3호 케이크\n",
            "* 디자인: 결혼 기념일을 위한 디자인 (예: 손님 이름, 결혼 날짜 등)\n",
            "* 픽업 날짜 및 시간: 2023년 10월 28일 오전 10시\n",
            "* 주문 가능한 옵션: \n",
            "    * 케이크 픽업\n",
            "    * 케이크 배달\n",
            "* 가격: 15,000원\n",
            "* 추가 옵션: \n",
            "    * 케이크 장식 (예: 꽃, 글자, 사진 등)\n",
            "    * 케이크 포장 (예: 핸드메이드 포장, 특별한 포장 등)\n",
            "\n",
            "고객님의 요청에 맞춰 케이크를 제작해 드리겠습니다.\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 11.90s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m19s\u001b[0m 2s/step - loss: 0.4444 - sparse_categorical_accuracy: 0.8038  \n",
            "Epoch 14/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 648ms/step - loss: 0.4074 - sparse_categorical_accuracy: 0.8195\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. \n",
            "다음과 같은 종류가 있습니다.\n",
            "\n",
            "* 3호 케이크: 12인분\n",
            "* 디자인: [케이크 디자인 예시: 사랑스러운 로맨틱한 디자인]\n",
            "* 픽업 날짜 및 시간: [픽업 날짜 및 시간 예시: 2023년 12월 25일 오전 10시]\n",
            "* 가격: 15,000원\n",
            "\n",
            "주문하시면 상세한 정보와 함께 케이크 디자인을 함께 보여드리겠습니다.\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 8.32s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 2s/step - loss: 0.4058 - sparse_categorical_accuracy: 0.8199  \n",
            "Epoch 15/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.3711 - sparse_categorical_accuracy: 0.8331\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. \n",
            "3호 케이크는 12월 25일 주문 가능합니다.\n",
            "다음과 같은 디자인을 원하시나요?\n",
            "\n",
            "* 흰색 케이크, 꽃 장식\n",
            "* 빨간색 케이크, 딸기 장식\n",
            "* 초록색 케이크, 초콜릿 장식\n",
            "\n",
            "혹시 다른 디자인이 있으시면 말씀해주세요.<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 5.83s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 1s/step - loss: 0.3696 - sparse_categorical_accuracy: 0.8336  \n",
            "Epoch 16/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.3365 - sparse_categorical_accuracy: 0.8525\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. 원하시는 디자인이나 특별한 요청 사항이 있으시면 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.28s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 1s/step - loss: 0.3353 - sparse_categorical_accuracy: 0.8529  \n",
            "Epoch 17/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 647ms/step - loss: 0.3060 - sparse_categorical_accuracy: 0.8617\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. 원하시는 디자인이나 특별한 요청 사항이 있으시면 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.28s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 1s/step - loss: 0.3049 - sparse_categorical_accuracy: 0.8621  \n",
            "Epoch 18/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 647ms/step - loss: 0.2785 - sparse_categorical_accuracy: 0.8732\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. 원하시는 디자인이나 특별한 요청 사항이 있으시면 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.28s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 1s/step - loss: 0.2775 - sparse_categorical_accuracy: 0.8739  \n",
            "Epoch 19/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.2531 - sparse_categorical_accuracy: 0.8840\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. 원하시는 디자인이나 특별한 요청 사항이 있으시면 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.28s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m10s\u001b[0m 1s/step - loss: 0.2522 - sparse_categorical_accuracy: 0.8847  \n",
            "Epoch 20/20\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 646ms/step - loss: 0.2287 - sparse_categorical_accuracy: 0.8962\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다. 3호 케이크는 픽업 또는 배송 가능한지, 각 케이크에 대한 디자인이나 문구가 필요한지 등 추가 문의를 해주시면 감사하겠습니다.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 4.35s\n",
            "\u001b[1m10/10\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 1s/step - loss: 0.2278 - sparse_categorical_accuracy: 0.8969  \n"
          ]
        },
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAABAUElEQVR4nO3dd3wUdeL/8fduOiEJJZBGIBTpECBACMWaA1FRbBSVLihi5fyd8lXBO+9Ez3IWEBBpigqcCqIgiDlRSiCQANKlh5aElkJC2u78/kCjUQIsJJns7uv5eOzjIZOZyXsc1n07+5nPWAzDMAQAAGASq9kBAACAe6OMAAAAU1FGAACAqSgjAADAVJQRAABgKsoIAAAwFWUEAACYijICAABM5Wl2gMtht9t17NgxBQQEyGKxmB0HAABcBsMwlJOTo/DwcFmtZV//cIoycuzYMUVGRpodAwAAXIHDhw+rXr16Zf7cKcpIQECApPMHExgYaHIaAABwObKzsxUZGVnyOV4Wpygjv341ExgYSBkBAMDJXGqIBQNYAQCAqSgjAADAVJQRAABgKsoIAAAwFWUEAACYijICAABMRRkBAACmoowAAABTUUYAAICpKCMAAMBUlBEAAGAqyggAADCVW5eRZdvS9OS8TcrJLzI7CgAAbsspntpbEc4V2vTcwq06lVuolNRMvTOwvdpF1jA7FgAAbsdtr4z4eXto2qAYRdTwU+rpPN0zZa2mrNwnu90wOxoAAG7FbcuIJHWMqqWlT/TQrW3CVGw39OqyXRo8M0kZ2flmRwMAwG24dRmRpCA/L026r71evbuN/Lw8tHrvSd389ip9vyvD7GgAALgFty8jkmSxWNS/U3199Vh3tQgL1OncQg2bvUF//2q7CoptZscDAMClUUZ+p0nd6lr4SFcN6xYlSZq15qDunLxWezPOmhsMAAAXRhn5A18vD03o00ozhnRULX9v7TierT7vrtb8DakyDAa3AgBQ3igjZbipRYi+eaKHujWprXNFNj3z+VY9+ukmZZ1jThIAAMoTZeQiQgJ99dHwWD1zc3N5Wi1a8tNx3fL2KiUfOm12NAAAXAZl5BKsVotGX99Y/304TpG1/HQ085z6TVundxP2yMacJAAAXDXKyGVqX7+mlj7eQ3e0C5fNbuiNFT/rvunrdDzrnNnRAABwapQRBwT4eumt/u30xr3RqubtofUHTqv326v07fY0s6MBAOC0KCMOslgsujumnpY83kOtIwKVmVekUR8l64VF25RfxJwkAAA4ijJyhRoG++uL0d00skdDSdJH6w7pjklr9HN6jsnJAABwLpSRq+DtadVzt7bUnOGdFVzdW7vTc9Tn3dWau+4Qc5IAAHCZKCPl4LqmdfTNE9fq2qZ1VFBs1/OLtunhucnKzCs0OxoAAFUeZaSc1Anw0eyhnfT8rS3k5WHR8u3p6v32KiUdYE4SAAAuhjJSjqxWix7s0UhfjO6mhsH+Op6Vrwc+WK9Ve06YHQ0AgCqLMlIB2tQL0tePdVfPliEqtNk16sNkJR86Y3YsAACqJMpIBfH38dS797VXj2uCda7IpmGzkrTzeLbZsQAAqHIoIxXIx9ND0wbFKKZBTWXnF2vQjCQdPJlrdiwAAKoUykgFq+btqZlDO6lFWKBOni3Q/R+sZwp5AAB+hzJSCYL8vPTh8M5qGOyvo5nn9MAH63XqbIHZsQAAqBIoI5WkToCPPhrRWWFBvtp3IldDZ21QTn6R2bEAADAdZaQS1atZTR+NiFUtf29tPZqlEXM28jwbAIDbo4xUsiZ1q+vD4Z0V4OOppAOn9cjHKSqy2c2OBQCAaSgjJmgdEaQZQzvJx9Oq/+3K0F8XbJHNzrNsAADuiTJiks4Na2nqAzHytFq0eMsxjf9yGw/XAwC4JcqIiW5oXlf/6d9OFov08fpU/Xv5brMjAQBQ6SgjJusTHa6X72wjSZqycp+m/rDP5EQAAFQuykgVMLBzfY3r3VyS9Mo3u/TJ+lSTEwEAUHkoI1XEQ9c11iPXN5YkPbdoqxZvOWZyIgAAKofDZeTHH39Unz59FB4eLovFokWLFl1ym5UrV6pDhw7y8fFRkyZNNHv27CuI6vr+X69meqBLfRmGNHb+Zn2/K8PsSAAAVDiHy0hubq6io6M1efLky1r/wIEDuvXWW3XDDTdo8+bNevLJJ/Xggw9q+fLlDod1dRaLRf+4vbXuaBeuYruhh+cma/3+U2bHAgCgQlmMq7if1GKxaOHCherbt2+Z6zzzzDNasmSJtm3bVrJswIAByszM1LJlyy7r92RnZysoKEhZWVkKDAy80rhOo8hm18MfJSthV4YCfDz16aguah0RZHYsAAAccrmf3xU+ZiQxMVHx8fGllvXq1UuJiYkV/audlpeHVZPv76DYhrWUU1CswTOTtDfjrNmxAACoEBVeRtLS0hQSElJqWUhIiLKzs3Xu3LkLblNQUKDs7OxSL3fj6+WhD4Z0VJuIIJ3OLdSgGet15Eye2bEAACh3VfJumokTJyooKKjkFRkZaXYkUwT4emnO8M5qUre6jmfl64EP1utEToHZsQAAKFcVXkZCQ0OVnp5eall6eroCAwPl5+d3wW3GjRunrKysktfhw4crOmaVVcvfW3NHxKpeTT8dPJWnwTOTlJVXZHYsAADKTYWXkbi4OCUkJJRatmLFCsXFxZW5jY+PjwIDA0u93FlokK/mjohVcHUf7TyerWGzk5RXWGx2LAAAyoXDZeTs2bPavHmzNm/eLOn8rbubN29Waur5WUPHjRunwYMHl6z/8MMPa//+/frb3/6mXbt26b333tOCBQv01FNPlc8RuImoYH99NKKzAn09lZKaqYc+SlZBsc3sWAAAXDWHy8jGjRvVvn17tW/fXpI0duxYtW/fXuPHj5ckHT9+vKSYSFLDhg21ZMkSrVixQtHR0XrjjTf0wQcfqFevXuV0CO6jRVigZg/vrGreHlq156SenLdZxTa72bEAALgqVzXPSGVxt3lGLmX1npMaPnuDCm123Rdbv+RBewAAVCVVZp4RlL/u1wTrnYHtZbFIn6xP1cfrD5kdCQCAK0YZcVI3tw7V/+vVTJL04uLtSj502uREAABcGcqIExt9XWPd0iZURTZDD89NUXp2vtmRAABwGGXEiVksFr12T7SahQToRE6BHp7LHTYAAOdDGXFy/j6emjYoRoG+ntqUmqkXF+8wOxIAAA6hjLiAqGD/kgGtnyal6pP1qZfeCACAKoIy4iKub1ZXT/c8P6B1wuJtSj50xuREAABcHsqIC3nk+sbq3fr8gNbRc5MZ0AoAcAqUERdisVj0+r3RahpSXRk5BRo9N1mFxczQCgCo2igjLsbfx1PvD+pY8gybF7/abnYkAAAuijLigqKC/fX272Zo/TSJAa0AgKqLMuKibvj9gNYvtysllQGtAICqiTLiwh65vrFubhWqQptdD3+UrAwGtAIAqiDKiAuzWCx6vV+0rql7fkDrIx+nMKAVAFDlUEZcXHUfT70/uKMCfD218dAZ/Z0BrQCAKoYy4gYaBvvrnQHnB7R+vD5V8xjQCgCoQigjbuKG5nX11780lSSNZ0ArAKAKoYy4kUeub6JerUJUaLNr9NxkZeQwoBUAYD7KiBuxWi16o187NalbXenZBXpkLgNaAQDmo4y4meo+nnp/UEzJgNaXvt5hdiQAgJujjLihRnWq6+0B7WSxSB+tO6QFGw6bHQkA4MYoI27qxuYheir+/IDW5xdt0+bDmeYGAgC4LcqIG3v0hibq2TLktxlaGdAKADABZcSNWa0Wvdn//IDWtOx8jWGGVgCACSgjbq66j6emDYpRgI+nNhw8o38uYUArAKByUUagxnWq660B7SRJHyYe0oKNDGgFAFQeyggkSTe1KD2gdQsDWgEAlYQyghKP3dhEf2kZosJiux76KFkncgrMjgQAcAOUEZSwWi16s1+0GtfxLxnQWmRjQCsAoGJRRlBKgK+X3h/cUQE+nko6eFrPL9wmwzDMjgUAcGGUEfxJ4zrV9fbAdrJapPkbD+vthD1mRwIAuDDKCC7oxuYh+scdrSVJb323hynjAQAVhjKCMj3QpYHG3NBYkjRu4VZ9vzvD5EQAAFdEGcFFPd2zme7qECGb3dCYj1P005FMsyMBAFwMZQQXZbFY9MpdbdXjmmDlFdo0fPYGpZ7KMzsWAMCFUEZwSd6eVk15IEYtwwJ18myhhsxK0uncQrNjAQBcBGUEl6W6j6dmD+ukiBp+OnAyVyPmbNC5QpvZsQAALoAygstWN9BXc4Z3UpCflzalZurxeZtkszMHCQDg6lBG4JAmdQM0Y0hHeXtatWJHuiYsZlI0AMDVoYzAYR2jaunt/u1ksUhz16XqvZX7zI4EAHBilBFckd5twjT+tpaSpNeW79YXKUdMTgQAcFaUEVyxYd0aatS1jSRJf/vsJ63ac8LkRAAAZ0QZwVV59ubm6hMdrmK7odFzU7T9WJbZkQAAToYygqtitVr0+r1tFdeots4WFGvorA06coZJ0QAAl48ygqvm4+mhqYNi1CwkQCdyCjRkZpIy85gUDQBweSgjKBdBfl6aPbyTwoJ8te9ErkZ+uFH5RUyKBgC4NMoIyk1YkJ9mD+usAF9PbTh4RmMXbJadSdEAAJdAGUG5ahYaoPcHdZS3h1VLt6bppSU7mBQNAHBRlBGUu7jGtfV6v2hJ0qw1B/XBqgMmJwIAVGWUEVSI26PD9X+3NJck/WvpTi3ecszkRACAqooyggozskcjDe0aJUl6esEWJe47ZW4gAECVRBlBhbFYLHrhtpbq3TpUhTa7Rn20UbvSss2OBQCoYigjqFAeVov+07+dOkXVVE5+sYbO3KDjWefMjgUAqEIoI6hwvl4emj64o5rUra607HwNnblBWeeKzI4FAKgiKCOoFDWqeWv2sE6qG+Cj3ek5euijjSooZlI0AABlBJWoXs1qmjWsk6r7eGrd/tN6+r8/MSkaAIAygsrVKjxIUx7oIE+rRV9tOaa/ff6TbBQSAHBrlBFUuh7X1NGb/dvJapE+Sz6i//ffLRQSAHBjlBGY4vbocL07sIM8rBZ9semoxi7YrGKb3exYAAATUEZgmlvbhmnyfe3labXoy83H9MT8zSqikACA26GMwFQ3tw7Te/d3kJeHRUt+Oq7HP91EIQEAN0MZgel6tgrV1Adi5O1h1Tfb0jTm4xQVFlNIAMBdUEZQJdzUIkTTBsfI29Oqb3ek65GPk5mHBADcBGUEVcYNzerqg8Ed5eNp1Xc7M/TwR8nKL6KQAICro4ygSrm2aR3NHNpJvl5Wfb/7hEZRSADA5VFGUOV0axKsWUM7y8/LQz/+fEIPztmoc4UUEgBwVVdURiZPnqyoqCj5+voqNjZWSUlJF13/rbfeUrNmzeTn56fIyEg99dRTys/Pv6LAcA9xjWtrzvDOqubtodV7T2r47A3KKyw2OxYAoAI4XEbmz5+vsWPHasKECUpJSVF0dLR69eqljIyMC67/ySef6Nlnn9WECRO0c+dOzZgxQ/Pnz9f//d//XXV4uLbODWvpw+GdVd3HU4n7T2norA06W0AhAQBX43AZefPNNzVy5EgNGzZMLVu21NSpU1WtWjXNnDnzguuvXbtW3bp103333aeoqCj17NlTAwcOvOTVFECSOkbV0ocjOivAx1NJB05r6Mwk5eQXmR0LAFCOHCojhYWFSk5OVnx8/G87sFoVHx+vxMTEC27TtWtXJScnl5SP/fv3a+nSpbrlllvK/D0FBQXKzs4u9YL76lC/puY+GKtAX09tPHRGg2cmKZtCAgAuw6EycvLkSdlsNoWEhJRaHhISorS0tAtuc9999+kf//iHunfvLi8vLzVu3FjXX3/9Rb+mmThxooKCgkpekZGRjsSEC4qOrKGPH+yiID8vbUrN1KAP1ivrHIUEAFxBhd9Ns3LlSr388st67733lJKSoi+++EJLlizRSy+9VOY248aNU1ZWVsnr8OHDFR0TTqBNvSB9MjJWNat5acuRLD3wwXpl5hWaHQsAcJUcKiPBwcHy8PBQenp6qeXp6ekKDQ294DYvvPCCBg0apAcffFBt2rTRnXfeqZdfflkTJ06U3X7hKb99fHwUGBhY6gVIUqvwIH0ysotq+Xtr69Es3Td9vc7kUkgAwJk5VEa8vb0VExOjhISEkmV2u10JCQmKi4u74DZ5eXmyWkv/Gg8PD0mSYRiO5gXUIixQn47souDq3tpxPFsDp6/TqbMFZscCAFwhh7+mGTt2rKZPn645c+Zo586dGj16tHJzczVs2DBJ0uDBgzVu3LiS9fv06aMpU6Zo3rx5OnDggFasWKEXXnhBffr0KSklgKOahQZo3qguqhPgo11pORo4fZ1O5FBIAMAZeTq6Qf/+/XXixAmNHz9eaWlpateunZYtW1YyqDU1NbXUlZDnn39eFotFzz//vI4ePao6deqoT58++te//lV+RwG31KTu+UJy3/R1+jn9rAZOX6dPRsaqboCv2dEAAA6wGE7wXUl2draCgoKUlZXF+BH8ycGTuRo4fZ2OZ+WrUR1/fTqyi0ICKSQAYLbL/fzm2TRwelHB/po/Kk4RNfy0/0SuBry/TsezzpkdCwBwmSgjcAn1a1fTvFFdVK+mnw6czFX/aet0NJNCAgDOgDIClxFZ63whqV+rmlJP56nf1ETtP3HW7FgAgEugjMCl1KtZTfMf6qKGwf46mnlO905N1NYjWWbHAgBcBGUELicsyE//fThOrSMCdSq3UAPeT9TqPSfNjgUAKANlBC4puLqPPh3ZRV0b11ZuoU3DZifp65+OmR0LAHABlBG4rABfL80a1km3tglTkc3QY59u0keJB82OBQD4A8oIXJqPp4feGdheD3SpL8OQXvhyu/6z4mceRQAAVQhlBC7Pw2rRS3e01pPx10iS3k7Yo+cXbZPNTiEBgKqAMgK3YLFY9GR8U73Ut7UsFunj9al67NMUFRTbzI4GAG6PMgK3MqhLA00a2EFeHhYt3ZqmYbM2KCe/yOxYAODWKCNwO7e2DdPsYZ3l7+2htftO8cRfADAZZQRuqVuTYM0bFafa/t7adjRb905dq8On88yOBQBuiTICt9WmXpA+G91V9Wr66eCpPN01Za12Hs82OxYAuB3KCNxaw2B/fT66q5qHBuhEToH6TUvU+v2nzI4FAG6FMgK3FxLoq/kPxalTVE3l5Bdr0Mwkfbs9zexYAOA2KCOApCA/L300IlbxLUJUWGzXw3OTNX9DqtmxAMAtUEaAX/h6eWjqAx10b0w92Q3pmc+36r2Ve5mtFQAqGGUE+B1PD6v+fU9bPXxdY0nSv5ft1ktf75Sd2VoBoMJQRoA/sFgserZ3cz1/awtJ0sw1BzR2wWYVFttNTgYArokyApThwR6N9J/+0fK0WrRo8zE9+OFG5RUWmx0LAFwOZQS4iDvb19P0IR3l62XVjz+f0H3T1+tMbqHZsQDApVBGgEu4oVldffxgFwX5eWnz4UzdOy1RxzLPmR0LAFwGZQS4DDENauqzh+MUFuSrvRlndfeUtdqTnmN2LABwCZQR4DJdExKgz0Z3VeM6/jqela+7p6xltlYAKAeUEcABETX89N+Hu6pD/RrKzi/WoBlJWrzlmNmxAMCpUUYAB9Xy99YnI7uoV6sQFdrsevzTTZr2wz4mRwOAK0QZAa6Ar5eH3rs/RsO6RUmSJn6zS+O/3C4bk6MBgMMoI8AV8rBaNKFPKz1/awtZLNJH6w7poY+Sda7QZnY0AHAqlBHgKj3Yo5Em39dB3p5WfbczXQOmr9PJswVmxwIAp0EZAcrBLW3C9PGDsapRzUtbDmfqrvfWav+Js2bHAgCnQBkBykmnqFr6fHRXRdbyU+rpPN09Za2SD502OxYAVHmUEaAcNa5TXV+M7qa29YJ0Jq9I901fr2XbjpsdCwCqNMoIUM7qBPho3qguuql5XRUU2zX64xTNXH3A7FgAUGVRRoAKUM3bU9MGxej+2PoyDOkfX+/QS1/vkJ1bfwHgTygjQAXx9LDqn31b6283N5MkzVh9QI9+mqL8Im79BYDfo4wAFchiseiR65vo7QHt5OVh0dKtaXrgg/U6k1todjQAqDIoI0AluKNdhD4cHqsAX09tPHRGd09Zq9RTeWbHAoAqgTICVJK4xrX1+eiuCg/y1f6TubpryhptOZxpdiwAMB1lBKhETUMCtHBMN7UMC9TJs4Ua8P46JexMNzsWAJiKMgJUspBAXy14OE7XNq2jc0U2jfxwo+auO2R2LAAwDWUEMEF1H0/NGNJR/TrWk92Qnl+0Ta8u28WtvwDcEmUEMImXh1Wv3t1WT8U3lSRNWblPTy3YrIJibv0F4F4oI4CJLBaLnoi/Rq/fGy1Pq0Vfbj6mITOTlHWuyOxoAFBpKCNAFXBPTD3NGtZJ1X08tW7/ad0zZa2OnOHWXwDugTICVBE9rqmjBQ/FKSTQR3syzqrv5DU89ReAW6CMAFVIy/BALXzkt1t/B76/Xgs3HTE7FgBUKMoIUMWE1/DTfx+OU8+WISq02fXU/C16bTl32gBwXZQRoAry9/HU1AdiNPr6xpKkyd/v0yMfpyivsNjkZABQ/igjQBVltVr0zM3N9ca90fL2sGrZ9jT1m5aotKx8s6MBQLmijABV3N0x9fTxyFjV8vfWtqPZun3Sav10JNPsWABQbigjgBPoFFVLX47ppqYh1ZWRU6B7pyZqyU/HzY4FAOWCMgI4icha1fT56K66oVkdFRTbNeaTFL2TsEeGwcBWAM6NMgI4kQBfL30wpJNGdG8oSXpzxc96Yt5m5RcxhTwA50UZAZyMh9WiF25rqYl3tZGn1aLFW45pwPvrlJHDwFYAzokyAjipgZ3r68MRnRXk56XNhzPVd9Ia7TiWbXYsAHAYZQRwYl0bB2vRmG5qFOyvY1n5umfqWq3YkW52LABwCGUEcHINg/218JFu6t4kWHmFNo36aKOm/rCPga0AnAZlBHABQdW8NGtYJz3Qpb4MQ3rlm136f5/9pIJiBrYCqPooI4CL8PKw6p992+jvt7eS1SJ9lnxEgz5I0qmzBWZHA4CLoowALmZI1yjNGtZZAT6eSjp4Wn3fW6Of03PMjgUAZaKMAC7ouqZ1tHBMV9WvVU2HT5/T3e+t1crdGWbHAoALoowALqpJ3QAtGtNNnRvWUk5BsYbP3qBZaw4wsBVAlUMZAVxYLX9vzR0Rq34d68luSH//aoeeW7RNRTa72dEAoARlBHBx3p5WvXp3W/3fLc1lsUifrE/VkJlJOpNbaHY0AJBEGQHcgsVi0ahrG2v6oI7y9/bQ2n2ndMfkNdqdxsBWAOa7ojIyefJkRUVFydfXV7GxsUpKSrro+pmZmRozZozCwsLk4+Ojpk2baunSpVcUGMCVi28Zos8f6arIWn5KPZ2nO99bo2Xb0syOBcDNOVxG5s+fr7Fjx2rChAlKSUlRdHS0evXqpYyMC4/ULyws1F/+8hcdPHhQn332mXbv3q3p06crIiLiqsMDcFzz0EAtHtNdXRvXVl6hTQ/PTdbb3+2R3c7AVgDmsBgODq2PjY1Vp06dNGnSJEmS3W5XZGSkHnvsMT377LN/Wn/q1Kl67bXXtGvXLnl5eV1RyOzsbAUFBSkrK0uBgYFXtA8ApRXb7PrX0p2ateagJOnmVqF6o1+0/H08zQ0GwGVc7ue3Q1dGCgsLlZycrPj4+N92YLUqPj5eiYmJF9xm8eLFiouL05gxYxQSEqLWrVvr5Zdfls1W9jTVBQUFys7OLvUCUL48Paya0KeV/n1PW3l7WLVse5ruem+tUk/lmR0NgJtxqIycPHlSNptNISEhpZaHhIQoLe3C3zvv379fn332mWw2m5YuXaoXXnhBb7zxhv75z3+W+XsmTpyooKCgkldkZKQjMQE4oF/HSM17qIvqBPhod3qObp+8Wmv2njQ7FgA3UuF309jtdtWtW1fvv/++YmJi1L9/fz333HOaOnVqmduMGzdOWVlZJa/Dhw9XdEzArXWoX1NfPdpd0ZE1lJlXpMEzk5ggDUClcaiMBAcHy8PDQ+np6aWWp6enKzQ09ILbhIWFqWnTpvLw8ChZ1qJFC6Wlpamw8MLzHPj4+CgwMLDUC0DFCg3y1fxRXXRXhwjZ7Ib+/tUO/Y0n/wKoBA6VEW9vb8XExCghIaFkmd1uV0JCguLi4i64Tbdu3bR3717Z7b/N+Pjzzz8rLCxM3t7eVxgbQEXw9fLQG/dG64XbWspqkf6bfEQD3l+njOx8s6MBcGEOf00zduxYTZ8+XXPmzNHOnTs1evRo5ebmatiwYZKkwYMHa9y4cSXrjx49WqdPn9YTTzyhn3/+WUuWLNHLL7+sMWPGlN9RACg3FotFI7o31JzhnRXk56VNqZnqM2m1Nh/ONDsaABfl8D18/fv314kTJzR+/HilpaWpXbt2WrZsWcmg1tTUVFmtv3WcyMhILV++XE899ZTatm2riIgIPfHEE3rmmWfK7ygAlLse19TRl2O6aeSHG7Un46z6TUvUxDvb6O6YemZHA+BiHJ5nxAzMMwKY52xBsZ6av1krdpwfKzaie0ON691cnh48TQLAxVXIPCMA3E91H09NeyBGj990jSRpxuoDGjprgzLzeNAegPJBGQFwSVarRWP/0lRT7u+gat4eWr33pO6YvEY/p/OgPQBXjzIC4LL1bhOmz0d3Vb2afjp0Kk93Tl6jb7fzoD0AV4cyAsAhLcICtfjR7oprVFu5hTaN+ihZ7yTwoD0AV44yAsBhtfy99eGIzhraNUqS9OaKnzXmkxTlFhSbGwyAU6KMALgiXh5WvXh7K/377vMP2vtmW5runrJWh0/zoD0AjqGMALgq/TpF6tNRXRRc3Ue70nJ0+6TVWsuD9gA4gDIC4KrFNKiprx7rprb1gnQmr0iDZibpg1X7edAegMtCGQFQLsKC/LTgobiSB+39c8lOPTFvs/IKGUcC4OIoIwDKza8P2vv77a3kabVo8ZZjuuu9tUo9xTgSAGWjjAAoVxaLRUO6RumTkb+NI+kzabVW7s4wOxqAKooyAqBCdG5YS18/1l3tImso61yRhs3eoMnf72UcCYA/oYwAqDChQb6a/1AXDexcX4YhvbZ8tx6em6yzzEcC4HcoIwAqlI+nhybe1UYT72ojbw+rlm9PV9/Ja7TvxFmzowGoIigjACrFwM71Nf+hLgoN9NXejLPqO2mNVuxINzsWgCqAMgKg0rSvX1NfPdZdnaNqKaegWCM/3Kg3v93Nc20AN0cZAVCp6gT46OORsSXPtXnnf3s1Ys4GZZ0rMjcYANNQRgBUul+fa/Nmv2j5eFr1/e4Tun3Sau1OyzE7GgATUEYAmOauDvX0+eiuiqjhp0On8tR38hp9/dMxs2MBqGSUEQCmah0RpK8e665uTWrrXJFNj36ySROX7lSxzW52NACVhDICwHS1/L01Z1hnPXRtI0nStB/3a8isJJ3OLTQ5GYDKQBkBUCV4elg17pYWendge/l5eWjN3lPq8+5qbTuaZXY0ABWMMgKgSukTHa6FY7qqQe1qOpp5TndPWasvUo6YHQtABaKMAKhymocGavGY7rqhWR0VFNs1dsEWvbh4u4oYRwK4JMoIgCopqJqXZgzppMdvbCJJmr32oO6fvl4ncgpMTgagvFFGAFRZVqtFY3s207RBMaru46mkg6d127urlHzotNnRAJQjygiAKq9Xq1AtGtNNjev4Kz27QP2mrdO7CXtkYxp5wCVQRgA4hSZ1q2vRmG66PTpcNruhN1b8rPumr9PxrHNmRwNwlSgjAJxGgK+X3h7QTq/fG61q3h5af+C0bn5rlZZtSzM7GoCrQBkB4FQsFovuiamnJY/3UJuIIGWdK9LDc5P13MKtOldoMzsegCtAGQHglBoG++vz0V016pdZWz9en6rbJ63WrrRsk5MBcBRlBIDT8va06v9uaaEPh3dWcHUf7ck4q9snrdGctQdlGAxuBZwFZQSA07u2aR0te7KHbmhWR4XFdk1YvF0jP9zIs20AJ0EZAeASgqv7aObQThp/W0t5e1j13c4M9X77R63de9LsaAAugTICwGVYLBYN795QC8d0VaNf5iS5f8Z6vbpsF1PJA1UYZQSAy2kVHqSvH+uuAZ0iZRjSlJX7dM/URB06lWt2NAAXQBkB4JKqeXvqlbvb6r37OyjQ11NbDmfq1ndWa9Gmo2ZHA/AHlBEALu2WNmH65slr1Smqps4WFOvJ+Zs1dv5mnS0oNjsagF9QRgC4vIgafvp0ZBc9GX+NrBbpi01Hdds7q7TlcKbZ0QCIMgLATXh6WPVkfFPNfyhOETX8dPBUnu6eslZTf9gnOw/cA0xFGQHgVjpF1dLSx3voljahKrYbeuWbXRo8M0kZ2flmRwPcFmUEgNsJqualyfd10Ct3tZGfl4dW7z2pm99epYSd6WZHA9wSZQSAW7JYLBrQub6+eqy7WoYF6nRuoUbM2agXF29XfhEP3AMqE2UEgFtrUre6Fo7pquHdGkqSZq89qFveXqXkQ6dNTga4D8oIALfn4+mh8X1aatawTgoJ9NH+k7m6Z2qiXvp6h84VcpUEqGiUEQD4xQ3N6urbJ6/TPTH1ZBjSjNUH1PvtH5V0gKskQEWijADA7wRV89Lr90Zr1rBOCg301cFTeer/fqJeXLxdeYVMlAZUBMoIAFzADc3q6tux15Y832b22oO6+a1VWrf/lNnRAJdDGQGAMgT6eumVu9tqzvDOCg/yVerpPA14f53Gf7lNuUwnD5QbyggAXMJ1Teto+VPXamDn+pKkDxMPqddbP2rt3pMmJwNcA2UEAC5DgK+XJt7VRnNHxCqihp+OnDmn+z5Yr+cWbuWhe8BVoowAgAO6XxOs5U9dq0FdGkiSPl6fql7/+VGr93CVBLhSlBEAcFB1H0+91Le1PhkZq8hafjqaeU4PzFivcV/8pOz8IrPjAU6HMgIAV6hr42Ate+JaDe0aJUn6NOmwev3nR63cnWFuMMDJUEYA4Cr4+3jqxdtbaf6oLmpQu5qOZ+Vr6KwN+ttnW5R1jqskwOWgjABAOYhtVFvLnrhWw7s1lMUiLdh4RL3+86P+t4snAQOXQhkBgHLi533+GTf/fShODYP9lZadr+GzN+qvC7YoK4+rJEBZKCMAUM46RtXS0sd7aGSP81dJPk85or/85wd9t4OrJMCFUEYAoAL4eXvouVtb6rOHu6pRHX9l5BTowQ836ol5m3TybIHZ8YAqhTICABUopkFNLX28hx66rpGsFunLzcd04+sr9fH6Q7LbDbPjAVUCZQQAKpivl4fG9W6hhY90U+uIQGXnF+u5hdt099S12n4sy+x4gOkoIwBQSaIja+jLMd31Yp+Wqu7jqU2pmerz7mq99PUOppSHW6OMAEAl8rBaNLRbQyX89Trd2jZMdkOasfqA4t/4Qd9sPS7D4KsbuB/KCACYICTQV5Pv66A5wzurfq1qSsvO1+iPUzR89gYdPp1ndjygUlFGAMBE1zWto2+fulaP39hEXh4Wfb/7hP7ynx80+fu9Kiy2mx0PqBSUEQAwma+Xh8b2bKZvnrhWcY1qK7/IrteW79Yt76zSuv2nzI4HVLgrKiOTJ09WVFSUfH19FRsbq6SkpMvabt68ebJYLOrbt++V/FoAcGlN6lbXJyNj9Vb/dgqu7q29GWc14P11+uuCLTrF3CRwYQ6Xkfnz52vs2LGaMGGCUlJSFB0drV69eikj4+JPqTx48KCefvpp9ejR44rDAoCrs1gs6ts+Qgljr9f9sfVLZnC98Y0f9GlSKnOTwCVZDAeHbsfGxqpTp06aNGmSJMlutysyMlKPPfaYnn322QtuY7PZdO2112r48OFatWqVMjMztWjRosv+ndnZ2QoKClJWVpYCAwMdiQsATm1T6hk9t3CbdhzPliR1qF9D/7qzjVqE8d9CVH2X+/nt0JWRwsJCJScnKz4+/rcdWK2Kj49XYmJimdv94x//UN26dTVixIjL+j0FBQXKzs4u9QIAd9S+fk0tfrSbXritpfy9PZSSmqnb3l2tfy3ZoVzmJoGLcKiMnDx5UjabTSEhIaWWh4SEKC0t7YLbrF69WjNmzND06dMv+/dMnDhRQUFBJa/IyEhHYgKAS/H0sGpE94ZK+Ov1uqVNqGx2Q9NXHVD8mz9o2bY05iaB06vQu2lycnI0aNAgTZ8+XcHBwZe93bhx45SVlVXyOnz4cAWmBADnEBrkq/fuj9GsoZ0UWctPx7Py9fDcZD04ZyNzk8CpeTqycnBwsDw8PJSeXvox2Onp6QoNDf3T+vv27dPBgwfVp0+fkmV2+/n75j09PbV79241btz4T9v5+PjIx8fHkWgA4DZuaF5X3za6TpO/36tpP+5Twq4Mrdl3Uk/c1FQjujeUtyezNsC5OPQ31tvbWzExMUpISChZZrfblZCQoLi4uD+t37x5c23dulWbN28ued1+++264YYbtHnzZr5+AYAr5Oftoad7NdM3T/RQbMNayi+y69Vlu3Tz2z/qux3pfHUDp+LQlRFJGjt2rIYMGaKOHTuqc+fOeuutt5Sbm6thw4ZJkgYPHqyIiAhNnDhRvr6+at26danta9SoIUl/Wg4AcFyTugGaN6qLFm46qn8t2an9J3L14Icb1bVxbT13awu1Cg8yOyJwSQ6Xkf79++vEiRMaP3680tLS1K5dOy1btqxkUGtqaqqsVi4RAkBlsVgsuqtDPcW3DNGUlfs0Y/UBrd13Sre9u1r3dKinp3s1U0igr9kxgTI5PM+IGZhnBAAu3+HTeXpt+W4t3nJMkuTn5aGHrmukUdc2UjVvh/8fFLhil/v5TRkBABeVknpG//x6h1JSMyVJIYE+erpnM93doZ6sVou54eAWKCMAABmGoSVbj+vVZbt0+PQ5SVKr8EA9d2sLdW18+VMuAFeCMgIAKFFQbNOctQf1bsJe5fwyc2t8ixCNu6W5GtepbnI6uCrKCADgT06dLdDbCXv08fpU2eyGPK0WPdClgZ646RrV9Pc2Ox5cDGUEAFCmvRlnNXHpTiXsOv/E9UBfTz124zUa3LWBfDw9TE4HV0EZAQBc0pq9J/XPJTu185enAtevVU3P9m6u3q1DZbEwyBVXhzICALgsNruhz5OP6PVvdysjp0CS1LFBTT1/W0u1i6xhbjg4NcoIAMAhuQXFmvbjfr3/4z7lF51/jtgd7cL1t5ubK6KGn8np4IwoIwCAK3I865xeX/6zvth0RIYh+XhaNaJ7Q42+vrECfL3MjgcnQhkBAFyVbUez9M8lO7Ru/2lJUnB1bz1+0zUa0Kk+TwbGZaGMAACummEYWrEjXRO/2aUDJ3MlSRE1/PRk/DW6s32EPD0oJSgbZQQAUG4Ki+2av/Gw3k3YUzLItVEdf/31L83Uu3Uo08vjgigjAIByd67Qpo/WHdR7K/cpM69IktQyLFBP92qqG5rV5XZglEIZAQBUmJz8Is1YfUAfrDqgs79MLx/ToKae7tlMcY1rm5wOVQVlBABQ4c7kFmrqD/s0e+1BFRSfvx24xzXBerpnM0UzR4nbo4wAACpNena+Jv1vr+ZtSFWR7fzHSs+WIfprz2ZqFhpgcjqYhTICAKh0h0/n6a3v9mjhpiOyG5LFIt0RHa4n45sqKtjf7HioZJQRAIBp9mbk6M0VP2vp1jRJkofVon4d6+mxG69ROLO5ug3KCADAdNuOZun1b3dr5e4TkiRvT6seiG2gR25orODqPianQ0WjjAAAqowNB0/rteW7lXTg/Gyu1bw9NLxbQ428tpGC/Jhi3lVRRgAAVYphGFq156ReW75bW49mSZICfT310HWNNaxblKp5e5qcEOWNMgIAqJIMw9Dy7el649vd2pNxVpIUXN1HY25orIGd68vXy8PkhCgvlBEAQJVmsxtavOWo/rNij1JP50mSavt7a1i3KA3qEqWganx94+woIwAAp1Bks2vBxsOasnKfjpw5J0ny9/bQ/V0aaET3hgoJ9DU5Ia4UZQQA4FSKbXYt2XpcU1bu0660HEmSt4dVd3WI0KhrG6lRneomJ4SjKCMAAKdkGIZW7j6hKSv3Keng+btvLBapd+tQPXxdY7WtV8PcgLhslBEAgNPbePC0pv6wT9/tzChZ1r1JsEZf31hdG9fmKcFVHGUEAOAydqflaNoP+/TllmOy2c9/bLWtF6TR1zVWz1ah8rBSSqoiyggAwOUcOZOnD1Yd0LwNqcovOv+U4EbB/nroukbq2z5CPp7cFlyVUEYAAC7r1NkCzVl7UHMSDynrXJEkKSTQRyO6N9R9sQ1U3YcJ1KoCyggAwOWdLSjWvKRUfbDqgNKy8yWdn9V1cFyUhnaL4vk3JqOMAADcRmGxXYs2HdXUH/dp/4lcSZKPp1X9O0VqZI9GiqxVzeSE7okyAgBwOza7oRU70jRl5T5tOXL++TceVov6tA3TqGsbq2U4nyGViTICAHBbhmEocd8pTflhn1btOVmyvEujWhrataHiW9SVp4fVxITugTICAICkbUezNOWHfVq2La3ktuCIGn4aFNdAAzpFqkY1b5MTui7KCAAAv3Ms85zmrjukT5NSdSbv/B04vl5W3dk+QkO6Rql5KJ8v5Y0yAgDABeQX2bR4yzHNWnNQO49nlyyPa1RbQ7tFKb5FCJOolRPKCAAAF2EYhjYcPKPZaw9o+fb0Ul/hDOnaQP071ldQNS+TUzo3yggAAJep7K9w6mlo1yg1Cw0wOaFzoowAAOCg/CKbFm8+pllrS3+F07VxbQ3tGqWb+ArHIZQRAACukGEYSjpwWrPXHtTy7Wn65Rsc1avpp8FxfIVzuSgjAACUg6OZ5/RR4iHN25CqzF++wvHz8tCdHSI0tGuUmobwFU5ZKCMAAJSj/CKbvtx8VLPWHNSutJyS5d2a1NaQOL7CuRDKCAAAFcAwDK0/cFqz1xzUtzt++wonooaf+neKVL+OkQoN8jU3ZBVBGQEAoIIdOZOnuetSS32FY7VINzYP0X2xkbquaV23vlpCGQEAoJLkF9m0bFuaPklKVdKB0yXLw4N81b9TffXrVE9hQX4mJjQHZQQAABPszcjRp0mH9XnKkT9cLamr+2Lru9XVEsoIAAAmyi+yafn2NH28/s9XS/p1ilT/TpEuf7WEMgIAQBWxN+Os5iWl6rMLXC0Z2Lm+rm/mmldLKCMAAFQxv14t+WR9qtb/7mpJWJBvyZ044TVc52oJZQQAgCps34lfrpYkHyl5Ho7VIt3Q7NerJXXk6WE1OeXVoYwAAOAECoptWr49XZ+sP6R1+0tfLenX8fzYEme9WkIZAQDAyew/cVbzNhzWZ8lHdDq3UNL5qyXXN6ur/p0idWPzuvJyoqsllBEAAJxUQbFN325P1yfrU5W4/1TJ8uDq3rqzfYTu7RjpFM/EoYwAAOAC9p84q/kbD+uLlKM6kVNQsrxdZA316xip26LDFOhbNZ8gTBkBAMCFFNvs+uHnE1qw8bASdmao+JeH4vh6WdW7dZju7VhPXRrWlrUK3SJMGQEAwEWdPFugRZuOav6Gw9qTcbZkeWQtP90bE6m7Y+opogoMeqWMAADg4gzD0JYjWVqw8bC+2nxMOQXFkiSLRereJFj9OkbqLy1D5OvlYUo+yggAAG7kXKFNy7Yf14INR0oNeg3y81LfduG6t2OkWkcEVWomyggAAG4q9VSePks+f4vwsaz8kuUtwwLVr2M93dEuQjX9vSs8B2UEAAA3Z7MbWrP3pBZsPKxvt6er0GaXJHl7WPWXViHq1zFS3ZsEV9hzcSgjAACgRGZeob7cfEwLNh7W9mPZJcvDgnx1d4d6Ghhbv9wHvVJGAADABW07mqXPko9o4aajyjp3/rk4s4Z10g3N6pbr77ncz2/Pcv2tAACgymsdEaTWEUF6tndzfbczXSt2pOvaa+qYlocyAgCAm/L18tBtbcN1W9twU3M4z9N2AACAS7qiMjJ58mRFRUXJ19dXsbGxSkpKKnPd6dOnq0ePHqpZs6Zq1qyp+Pj4i64PAADci8NlZP78+Ro7dqwmTJiglJQURUdHq1evXsrIyLjg+itXrtTAgQP1/fffKzExUZGRkerZs6eOHj161eEBAIDzc/humtjYWHXq1EmTJk2SJNntdkVGRuqxxx7Ts88+e8ntbTabatasqUmTJmnw4MGX9Tu5mwYAAOdzuZ/fDl0ZKSwsVHJysuLj43/bgdWq+Ph4JSYmXtY+8vLyVFRUpFq1apW5TkFBgbKzs0u9AACAa3KojJw8eVI2m00hISGlloeEhCgtLe2y9vHMM88oPDy8VKH5o4kTJyooKKjkFRkZ6UhMAADgRCr1bppXXnlF8+bN08KFC+Xr61vmeuPGjVNWVlbJ6/Dhw5WYEgAAVCaH5hkJDg6Wh4eH0tPTSy1PT09XaGjoRbd9/fXX9corr+i7775T27ZtL7quj4+PfHx8HIkGAACclENXRry9vRUTE6OEhISSZXa7XQkJCYqLiytzu3//+9966aWXtGzZMnXs2PHK0wIAAJfj8AysY8eO1ZAhQ9SxY0d17txZb731lnJzczVs2DBJ0uDBgxUREaGJEydKkl599VWNHz9en3zyiaKiokrGllSvXl3Vq1cvx0MBAADOyOEy0r9/f504cULjx49XWlqa2rVrp2XLlpUMak1NTZXV+tsFlylTpqiwsFD33HNPqf1MmDBBL7744tWlBwAATo+n9gIAgApRIfOMAAAAlDeneGrvrxdvmPwMAADn8evn9qW+hHGKMpKTkyNJTH4GAIATysnJUVBQUJk/d4oxI3a7XceOHVNAQIAsFku57Tc7O1uRkZE6fPiwW4xFcafj5VhdlzsdL8fqutzleA3DUE5OjsLDw0vd3PJHTnFlxGq1ql69ehW2/8DAQJf+y/BH7nS8HKvrcqfj5Vhdlzsc78WuiPyKAawAAMBUlBEAAGAqty4jPj4+mjBhgts8B8edjpdjdV3udLwcq+tyt+O9FKcYwAoAAFyXW18ZAQAA5qOMAAAAU1FGAACAqSgjAADAVC5fRiZPnqyoqCj5+voqNjZWSUlJF13/v//9r5o3by5fX1+1adNGS5curaSkV2fixInq1KmTAgICVLduXfXt21e7d+++6DazZ8+WxWIp9fL19a2kxFfuxRdf/FPu5s2bX3QbZz2vUVFRfzpWi8WiMWPGXHB9ZzunP/74o/r06aPw8HBZLBYtWrSo1M8Nw9D48eMVFhYmPz8/xcfHa8+ePZfcr6Pv+8pwsWMtKirSM888ozZt2sjf31/h4eEaPHiwjh07dtF9Xsl7oTJc6rwOHTr0T7lvvvnmS+63Kp5X6dLHe6H3sMVi0WuvvVbmPqvqua0oLl1G5s+fr7Fjx2rChAlKSUlRdHS0evXqpYyMjAuuv3btWg0cOFAjRozQpk2b1LdvX/Xt21fbtm2r5OSO++GHHzRmzBitW7dOK1asUFFRkXr27Knc3NyLbhcYGKjjx4+XvA4dOlRJia9Oq1atSuVevXp1mes683ndsGFDqeNcsWKFJOnee+8tcxtnOqe5ubmKjo7W5MmTL/jzf//733rnnXc0depUrV+/Xv7+/urVq5fy8/PL3Kej7/vKcrFjzcvLU0pKil544QWlpKToiy++0O7du3X77bdfcr+OvBcqy6XOqyTdfPPNpXJ/+umnF91nVT2v0qWP9/fHefz4cc2cOVMWi0V33333RfdbFc9thTFcWOfOnY0xY8aU/Nlmsxnh4eHGxIkTL7h+v379jFtvvbXUstjYWOOhhx6q0JwVISMjw5Bk/PDDD2WuM2vWLCMoKKjyQpWTCRMmGNHR0Ze9viud1yeeeMJo3LixYbfbL/hzZz2nhmEYkoyFCxeW/NlutxuhoaHGa6+9VrIsMzPT8PHxMT799NMy9+Po+94MfzzWC0lKSjIkGYcOHSpzHUffC2a40LEOGTLEuOOOOxzajzOcV8O4vHN7xx13GDfeeONF13GGc1ueXPbKSGFhoZKTkxUfH1+yzGq1Kj4+XomJiRfcJjExsdT6ktSrV68y16/KsrKyJEm1atW66Hpnz55VgwYNFBkZqTvuuEPbt2+vjHhXbc+ePQoPD1ejRo10//33KzU1tcx1XeW8FhYWau7cuRo+fPhFHxjprOf0jw4cOKC0tLRS5y4oKEixsbFlnrsred9XVVlZWbJYLKpRo8ZF13PkvVCVrFy5UnXr1lWzZs00evRonTp1qsx1Xem8pqena8mSJRoxYsQl13XWc3slXLaMnDx5UjabTSEhIaWWh4SEKC0t7YLbpKWlObR+VWW32/Xkk0+qW7duat26dZnrNWvWTDNnztSXX36puXPnym63q2vXrjpy5EglpnVcbGysZs+erWXLlmnKlCk6cOCAevTooZycnAuu7yrnddGiRcrMzNTQoUPLXMdZz+mF/Hp+HDl3V/K+r4ry8/P1zDPPaODAgRd9iJqj74Wq4uabb9aHH36ohIQEvfrqq/rhhx/Uu3dv2Wy2C67vKudVkubMmaOAgADdddddF13PWc/tlXKKp/bCMWPGjNG2bdsu+f1iXFyc4uLiSv7ctWtXtWjRQtOmTdNLL71U0TGvWO/evUv+uW3btoqNjVWDBg20YMGCy/q/DWc1Y8YM9e7dW+Hh4WWu46znFL8pKipSv379ZBiGpkyZctF1nfW9MGDAgJJ/btOmjdq2bavGjRtr5cqVuummm0xMVvFmzpyp+++//5IDy5313F4pl70yEhwcLA8PD6Wnp5danp6ertDQ0AtuExoa6tD6VdGjjz6qr7/+Wt9//73q1avn0LZeXl5q37699u7dW0HpKkaNGjXUtGnTMnO7wnk9dOiQvvvuOz344IMObees51RSyflx5Nxdyfu+Kvm1iBw6dEgrVqxw+NHyl3ovVFWNGjVScHBwmbmd/bz+atWqVdq9e7fD72PJec/t5XLZMuLt7a2YmBglJCSULLPb7UpISCj1f46/FxcXV2p9SVqxYkWZ61clhmHo0Ucf1cKFC/W///1PDRs2dHgfNptNW7duVVhYWAUkrDhnz57Vvn37ysztzOf1V7NmzVLdunV16623OrSds55TSWrYsKFCQ0NLnbvs7GytX7++zHN3Je/7quLXIrJnzx599913ql27tsP7uNR7oao6cuSITp06VWZuZz6vvzdjxgzFxMQoOjra4W2d9dxeNrNH0FakefPmGT4+Psbs2bONHTt2GKNGjTJq1KhhpKWlGYZhGIMGDTKeffbZkvXXrFljeHp6Gq+//rqxc+dOY8KECYaXl5exdetWsw7hso0ePdoICgoyVq5caRw/frzklZeXV7LOH4/373//u7F8+XJj3759RnJysjFgwADD19fX2L59uxmHcNn++te/GitXrjQOHDhgrFmzxoiPjzeCg4ONjIwMwzBc67waxvm7BurXr28888wzf/qZs5/TnJwcY9OmTcamTZsMScabb75pbNq0qeQOkldeecWoUaOG8eWXXxo//fSTcccddxgNGzY0zp07V7KPG2+80Xj33XdL/nyp971ZLnashYWFxu23327Uq1fP2Lx5c6n3cEFBQck+/nisl3ovmOVix5qTk2M8/fTTRmJionHgwAHju+++Mzp06GBcc801Rn5+fsk+nOW8Gsal/x4bhmFkZWUZ1apVM6ZMmXLBfTjLua0oLl1GDMMw3n33XaN+/fqGt7e30blzZ2PdunUlP7vuuuuMIUOGlFp/wYIFRtOmTQ1vb2+jVatWxpIlSyo58ZWRdMHXrFmzStb54/E++eSTJf9uQkJCjFtuucVISUmp/PAO6t+/vxEWFmZ4e3sbERERRv/+/Y29e/eW/NyVzqthGMby5csNScbu3bv/9DNnP6fff//9Bf/e/npMdrvdeOGFF4yQkBDDx8fHuOmmm/7076FBgwbGhAkTSi272PveLBc71gMHDpT5Hv7+++9L9vHHY73Ue8EsFzvWvLw8o2fPnkadOnUMLy8vo0GDBsbIkSP/VCqc5bwaxqX/HhuGYUybNs3w8/MzMjMzL7gPZzm3FcViGIZRoZdeAAAALsJlx4wAAADnQBkBAACmoowAAABTUUYAAICpKCMAAMBUlBEAAGAqyggAADAVZQQAAJiKMgIAAExFGQEAAKaijAAAAFNRRgAAgKn+P5chIWWn8BkHAAAAAElFTkSuQmCC",
            "text/plain": [
              "<Figure size 640x480 with 1 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "class CustomCallback(keras.callbacks.Callback):\n",
        "  def on_epoch_end(self, epoch, logs=None):\n",
        "    model_name = f\"/content/drive/MyDrive/{lora_name}_{lora_rank}_epoch{epoch+1}.lora.h5\"\n",
        "    gemma_lm.backbone.save_lora_weights(model_name)\n",
        "\n",
        "    # Evaluate\n",
        "    text_gen(\"다음에 대한 이메일 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")\n",
        "\n",
        "history = gemma_lm.fit(train, epochs=train_epoch, batch_size=2, callbacks=[CustomCallback()])\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "plt.plot(history.history['loss'])\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {
        "id": "gn5-eFiPUkSP"
      },
      "outputs": [],
      "source": [
        "# Example Code for Load LoRA\n",
        "'''\n",
        "train_epoch=17\n",
        "gemma_lm = keras_nlp.models.GemmaCausalLM.from_preset(model_id)\n",
        "# Use the same LoRA rank that you trained\n",
        "gemma_lm.backbone.enable_lora(rank=4)\n",
        "\n",
        "# Load pre-trained LoRA weights\n",
        "gemma_lm.backbone.load_lora_weights(f\"/content/drive/MyDrive/{lora_name}_{lora_rank}_epoch{train_epoch}.lora.h5\")\n",
        "'''"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ipg1u_wEKTxG"
      },
      "source": [
        "## Try a different sampler\n",
        "\n",
        "The top-K algorithm randomly picks the next token from the tokens of top K probability."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "metadata": {
        "id": "nV5mD_HqKZRF"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "고객님, 안녕하세요.\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다! 3호 케이크는 다양한 종류의 맛과 장식이 가능합니다. 원하시는 맛과 장식을 알려주시면 맞춤으로 디자인해 드리겠습니다.\n",
            "\n",
            "주문 날짜, 시간, 필요한 픽업 날짜 등 추가적인 문의를 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 5.88s\n",
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요.,\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다! 케이크 맛과 디자인에 대해 문의해주시면 맞춤 제작을 도와드리겠습니다. 혹시 특별히 원하시는 맛이나 디자인이 있으신가요?\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가장점 케이크 문의 담당자 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 4.75s\n",
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요,\n",
            "\n",
            "결혼기념일 3호 케이크 주문 가능합니다! 3호 케이크 1개를 주문하시려면, 픽업 날짜와 시간, 원하신 디자인 (혹은 사진)을 말씀해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 3.98s\n"
          ]
        }
      ],
      "source": [
        "gemma_lm.compile(sampler=\"top_k\")\n",
        "text_gen(\"다음에 대한 이메일 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")\n",
        "text_gen(\"다음에 대한 이메일 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")\n",
        "text_gen(\"다음에 대한 이메일 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3m1XaCrlMu3Y"
      },
      "source": [
        "Try a slight different prompts"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 6,
      "metadata": {
        "id": "qC-MLxYWM1HU"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 답장을 작성해줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            " 안녕하세요. 결혼기념일 3호 케이크 1개 주문 가능합니다. 원하시는 디자인이나 특별사항이 있으시면 말씀해주세요. 감사합니다. 😊<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 2.69s\n",
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "아래에 적절한 답장을 써줘.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요. 결혼기념일을 위한 3호 케이크 주문 가능합니다! 3호 케이크는 [가격]이며, 디자인은 다양하게 선택 가능합니다. 원하신 디자인과 함께 주문하시면 감사하겠습니다. 궁금한 점 있으시면 언제든지 문의해주세요. 😊 \n",
            "<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 4.41s\n",
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 관한 답장을 써주세요.\n",
            "\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\"<end_of_turn>\n",
            "<start_of_turn>model\n",
            "안녕하세요.,\n",
            "\n",
            "3호 케이크 1개 주문 가능합니다. 결혼기념일을 위한 특별한 케이크로 궁금하신 건, 정말 축하드립니다! \n",
            "\n",
            "주문하실 때 필요한 정보를 알려주시면 더욱 맞춤화해 드리려고 합니다. 예시로, 케이크 디자인, 크기, 문구, 픽업 날짜/시간 등을 말씀해주시면 됩니다.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 6.30s\n"
          ]
        }
      ],
      "source": [
        "text_gen(\"다음에 대한 답장을 작성해줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")\n",
        "text_gen(\"아래에 적절한 답장을 써줘.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")\n",
        "text_gen(\"다음에 관한 답장을 써주세요.\\n\\\"안녕하세요, 결혼기념일을 위해 3호 케이크 1개를 주문하고 싶은데 가능할까요?\\\"\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UePc572JSUmd"
      },
      "source": [
        "Try a different email inputs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 7,
      "metadata": {
        "id": "8n5LkXU8Sn6D"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "Gemma output:\n",
            "<start_of_turn>user\n",
            "다음에 대한 이메일 답장을 작성해줘.\n",
            "\"안녕하세요,\n",
            "\n",
            "6월 15일에 있을 행사 답례품으로 쿠키 & 머핀 세트를 대량 주문하고 싶습니다.\n",
            "\n",
            "수량: 50세트\n",
            "구성: 쿠키 2개 + 머핀 1개 (개별 포장)\n",
            "디자인: 심플하고 고급스러운 디자인 (리본 포장 등)\n",
            "문구: \"감사합니다\" 스티커 부착\n",
            "배송 날짜: 6월 14일\n",
            "대량 주문 할인 혜택이 있는지, 있다면 견적과 함께 배송 가능 여부를 알려주시면 감사하겠습니다.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "박철수 드림\" <end_of_turn>\n",
            "<start_of_turn>model\n",
            "박철수 님, 안녕하세요.\n",
            "\n",
            "6월 15일 행사 답례품 주문 문의 감사합니다.\n",
            "\n",
            "- 50 세트 대량 주문 가능합니다.\n",
            "- 쿠키 2개 + 머핀 1개 (개별 포장) 디자인, \"감사합니다\" 스티커 부착\n",
            "- 6월 14일 배송 가능합니다.\n",
            "- 대량 주문 시 10% 할인 혜택 제공됩니다.\n",
            "\n",
            "견적 및 배송 가능 여부를 원하시면 곧 전화해주세요.\n",
            "\n",
            "감사합니다.\n",
            "\n",
            "[가게 이름] 드림<end_of_turn>\n",
            "TOTAL TIME ELAPSED: 7.54s\n"
          ]
        }
      ],
      "source": [
        "text_gen(\"\"\"다음에 대한 이메일 답장을 작성해줘.\n",
        "\"안녕하세요,\n",
        "\n",
        "6월 15일에 있을 행사 답례품으로 쿠키 & 머핀 세트를 대량 주문하고 싶습니다.\n",
        "\n",
        "수량: 50세트\n",
        "구성: 쿠키 2개 + 머핀 1개 (개별 포장)\n",
        "디자인: 심플하고 고급스러운 디자인 (리본 포장 등)\n",
        "문구: \"감사합니다\" 스티커 부착\n",
        "배송 날짜: 6월 14일\n",
        "대량 주문 할인 혜택이 있는지, 있다면 견적과 함께 배송 가능 여부를 알려주시면 감사하겠습니다.\n",
        "\n",
        "감사합니다.\n",
        "\n",
        "박철수 드림\" \"\"\")\n"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "name": "spoken_language_tasks_with_gemma.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
